Contexto¶

Um banco de varejo gostaria de contratá-lo para criar um modelo de inadimplência de crédito para o portfólio de cartões de crédito. O banco espera que o modelo identifique os consumidores que provavelmente não pagam seus pagamentos com cartão de crédito nos próximos 12 meses. Este modelo será usado para reduzir as perdas futuras do banco. O banco está disposto para fornecer algumas amostras de dados que eles podem extrair atualmente de seus sistemas

Detalhes Sobre o Dataset¶

O signifcado de cada coluna do DataSet está sendo explicado abaixo:

  • 1 CARDHLDR Dummy variable, 1 if application for credit card accepted, 0 if not
  • 2 DEFAULT 1 if defaulted 0 if not (observed when CARDHLDR=1, 10,499 observations)
  • 3 AGE Age in years plus twelfths of a year
  • 4 ACADMOS months living at current address
  • 5 ADEPCNT 1 + number of dependents
  • 6 MAJORDRG Number of major derogatory reports
  • 7 MINORDRG Number of minor derogatory reports
  • 8 OWNRENT 1 if owns their home, 0 if rent
  • 9 INCOME Monthly income (divided by 10,000)
  • 10 SELFEMPL 1 if self employed, 0 if not
  • 11 INCPER Income divided by number of dependents
  • 12 EXP_INC Ratio of monthly credit card expenditure to yearly income
  • 13 SPENDING Average monthly credit card expenditure (for CARDHOLDER = 1)
  • 14 LOGSPEND Log of spending

Dataset Do Kaggle: https://www.kaggle.com/datasets/surekharamireddy/credit-data¶

In [1]:
## bibliotecas iniciais

import pandas as pd
import numpy as np
In [2]:
## importando o dataset

bank = pd.read_csv('credit_data.csv')

print(f'O dataset contém {bank.shape[0]} linhas e {bank.shape[1]} colunas.')
bank.head()
O dataset contém 13444 linhas e 14 colunas.
Out[2]:
CARDHLDR DEFAULT AGE ACADMOS ADEPCNT MAJORDRG MINORDRG OWNRENT INCOME SELFEMPL INCPER EXP_INC SPENDING LOGSPEND
0 0 0 27.250000 4 0 0 0 0 1200.000000 0 18000.0 0.000667
1 0 0 40.833332 111 3 0 0 1 4000.000000 0 13500.0 0.000222
2 1 0 37.666668 54 3 0 0 1 3666.666667 0 11300.0 0.033270 121.9896773 4.8039364
3 1 0 42.500000 60 3 0 0 1 2000.000000 0 17250.0 0.048427 96.8536213 4.5732008
4 1 0 21.333334 8 0 0 0 0 2916.666667 0 35000.0 0.016523 48.1916700 3.8751862
In [3]:
bank.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 13444 entries, 0 to 13443
Data columns (total 14 columns):
 #   Column     Non-Null Count  Dtype  
---  ------     --------------  -----  
 0   CARDHLDR   13444 non-null  int64  
 1   DEFAULT    13444 non-null  int64  
 2   AGE        13444 non-null  float64
 3   ACADMOS    13444 non-null  int64  
 4   ADEPCNT    13444 non-null  int64  
 5   MAJORDRG   13444 non-null  int64  
 6   MINORDRG   13444 non-null  int64  
 7   OWNRENT    13444 non-null  int64  
 8   INCOME     13444 non-null  float64
 9   SELFEMPL   13444 non-null  int64  
 10  INCPER     13444 non-null  float64
 11  EXP_INC    13444 non-null  float64
 12  SPENDING   13444 non-null  object 
 13  LOGSPEND   13444 non-null  object 
dtypes: float64(4), int64(8), object(2)
memory usage: 1.4+ MB
In [4]:
bank.describe()
Out[4]:
CARDHLDR DEFAULT AGE ACADMOS ADEPCNT MAJORDRG MINORDRG OWNRENT INCOME SELFEMPL INCPER EXP_INC
count 13444.000000 13444.000000 13444.000000 13444.000000 13444.000000 13444.000000 13444.000000 13444.000000 13444.000000 13444.000000 13444.000000 13444.000000
mean 0.780943 0.074085 33.471828 55.318878 1.017257 0.462809 0.290539 0.455965 2509.527819 0.057944 21719.680793 0.070974
std 0.413623 0.261919 10.226484 63.089729 1.279098 1.432724 0.767620 0.498076 1252.946716 0.233646 13591.209469 0.103922
min 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 50.000000 0.000000 362.500000 0.000088
25% 1.000000 0.000000 25.666666 12.000000 0.000000 0.000000 0.000000 0.000000 1666.666667 0.000000 12000.000000 0.002706
50% 1.000000 0.000000 31.500000 30.000000 1.000000 0.000000 0.000000 0.000000 2166.666667 0.000000 19000.000000 0.039286
75% 1.000000 0.000000 39.333332 72.000000 2.000000 0.000000 0.000000 1.000000 2916.666667 0.000000 27658.666504 0.095655
max 1.000000 1.000000 88.666664 576.000000 9.000000 22.000000 11.000000 1.000000 8333.250000 1.000000 150000.000000 2.037728
In [5]:
## alterando nomes das colunas

bank.columns = ['CARTAO_CRED', 'INADIMPLENCIA', 'IDADE', 'TEMPO_RESIDENCIA', 'DEPENDENTES', 'DEPREC_MAJOR', 'DEPREC_MINOR', 
               'CASA_PROPRIA', 'RENDA_MENSAL', 'AUTONOMO', 'RENDA/DEPENDENTES', 'EXP_INC', 'DESPESA_MENSAL_CC', 'REGISTRO_GASTOS']

bank
Out[5]:
CARTAO_CRED INADIMPLENCIA IDADE TEMPO_RESIDENCIA DEPENDENTES DEPREC_MAJOR DEPREC_MINOR CASA_PROPRIA RENDA_MENSAL AUTONOMO RENDA/DEPENDENTES EXP_INC DESPESA_MENSAL_CC REGISTRO_GASTOS
0 0 0 27.250000 4 0 0 0 0 1200.000000 0 18000.000000 0.000667
1 0 0 40.833332 111 3 0 0 1 4000.000000 0 13500.000000 0.000222
2 1 0 37.666668 54 3 0 0 1 3666.666667 0 11300.000000 0.033270 121.9896773 4.8039364
3 1 0 42.500000 60 3 0 0 1 2000.000000 0 17250.000000 0.048427 96.8536213 4.5732008
4 1 0 21.333334 8 0 0 0 0 2916.666667 0 35000.000000 0.016523 48.1916700 3.8751862
... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
13439 1 0 41.750000 12 1 0 0 0 2083.333333 1 12500.000000 0.047914 99.8216681 4.6033853
13440 1 0 48.500000 66 1 0 1 1 2583.333333 0 15500.000000 0.020469 52.8791657 3.9680094
13441 1 0 48.250000 2 2 0 0 1 3083.333333 0 12333.333008 0.111619 344.1574903 5.8410994
13442 1 0 24.833334 38 0 0 0 1 1416.666667 0 17000.000000 0.013096 18.5525005 2.9206046
13443 0 0 26.833334 12 2 8 3 1 1496.000000 0 5984.000000 0.000668

13444 rows × 14 columns

01 - Análise Exploratória Do Dataset¶

In [6]:
# Convertendo as colunas para float

bank['DESPESA_MENSAL_CC'] = pd.to_numeric(bank['DESPESA_MENSAL_CC'], errors='coerce')
bank['REGISTRO_GASTOS'] = pd.to_numeric(bank['REGISTRO_GASTOS'], errors='coerce')
In [7]:
bank.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 13444 entries, 0 to 13443
Data columns (total 14 columns):
 #   Column             Non-Null Count  Dtype  
---  ------             --------------  -----  
 0   CARTAO_CRED        13444 non-null  int64  
 1   INADIMPLENCIA      13444 non-null  int64  
 2   IDADE              13444 non-null  float64
 3   TEMPO_RESIDENCIA   13444 non-null  int64  
 4   DEPENDENTES        13444 non-null  int64  
 5   DEPREC_MAJOR       13444 non-null  int64  
 6   DEPREC_MINOR       13444 non-null  int64  
 7   CASA_PROPRIA       13444 non-null  int64  
 8   RENDA_MENSAL       13444 non-null  float64
 9   AUTONOMO           13444 non-null  int64  
 10  RENDA/DEPENDENTES  13444 non-null  float64
 11  EXP_INC            13444 non-null  float64
 12  DESPESA_MENSAL_CC  10499 non-null  float64
 13  REGISTRO_GASTOS    10499 non-null  float64
dtypes: float64(6), int64(8)
memory usage: 1.4 MB
In [8]:
## verificando nulos

bank.isnull().sum()
Out[8]:
CARTAO_CRED             0
INADIMPLENCIA           0
IDADE                   0
TEMPO_RESIDENCIA        0
DEPENDENTES             0
DEPREC_MAJOR            0
DEPREC_MINOR            0
CASA_PROPRIA            0
RENDA_MENSAL            0
AUTONOMO                0
RENDA/DEPENDENTES       0
EXP_INC                 0
DESPESA_MENSAL_CC    2945
REGISTRO_GASTOS      2945
dtype: int64
In [9]:
bank.head()
Out[9]:
CARTAO_CRED INADIMPLENCIA IDADE TEMPO_RESIDENCIA DEPENDENTES DEPREC_MAJOR DEPREC_MINOR CASA_PROPRIA RENDA_MENSAL AUTONOMO RENDA/DEPENDENTES EXP_INC DESPESA_MENSAL_CC REGISTRO_GASTOS
0 0 0 27.250000 4 0 0 0 0 1200.000000 0 18000.0 0.000667 NaN NaN
1 0 0 40.833332 111 3 0 0 1 4000.000000 0 13500.0 0.000222 NaN NaN
2 1 0 37.666668 54 3 0 0 1 3666.666667 0 11300.0 0.033270 121.989677 4.803936
3 1 0 42.500000 60 3 0 0 1 2000.000000 0 17250.0 0.048427 96.853621 4.573201
4 1 0 21.333334 8 0 0 0 0 2916.666667 0 35000.0 0.016523 48.191670 3.875186
In [10]:
import plotly.express as px
fig = px.histogram(data_frame=bank, x='RENDA_MENSAL')
fig.show()
In [11]:
## boxplot

fig = px.box(data_frame=bank, y='IDADE')
fig.show()
In [12]:
## boxplot para renda mensal

fig = px.box(data_frame=bank, y='RENDA_MENSAL')
fig.show()

Podemos ver alguns outliers em termos de idade e renda mensal, isso pode trazer desequilíbrio nas análises

In [13]:
fig = px.density_heatmap(data_frame=bank, x='RENDA/DEPENDENTES')
fig.show()
In [14]:
fig = px.histogram(data_frame=bank, x='CARTAO_CRED', color='CARTAO_CRED', barmode='group')
fig.show()
In [15]:
fig = px.histogram(bank, x='CARTAO_CRED', color='INADIMPLENCIA',
                   title='Relação entre Possui Cartão e Inadimplência',
                   labels={'Possui_Cartao': 'Possui Cartão', 'Inadimplente': 'Inadimplente'},
                   barmode='group')
fig.update_layout(bargap=0.2)  # Ajusta o espaço entre as barras agrupadas
fig.show()

02 - Breve Limpeza do Dataset¶

Ponto de atenção olhando as análises até então:

  • Existem menores de idade com cartão - descartar da base?
  • População SEM cartão não tem registro de inadimplência - podemos descartar essas pessoas para seguir apenas com quem TEVE cartão concedido.
In [16]:
abaixo_16 = bank[bank['IDADE'] < 16]

abaixo_16['CARTAO_CRED'].value_counts()
Out[16]:
CARTAO_CRED
1    38
0    16
Name: count, dtype: int64

Decidimos limpar a base para prosseguir, ou seja, retiramos população com menos de 16 anos e também as pessoas que NÃO possuem cartão.

  • Passo 01 da Limpeza
In [17]:
bank = bank[~bank.index.isin(abaixo_16.index)]

bank.shape
Out[17]:
(13390, 14)
  • Passo 02 da Limpeza
In [18]:
## filtrando o dataset e ficando apenas com quem teve cartão concedido

bank = bank[bank['CARTAO_CRED']==1]

Apesar de serem poucas colunas, vamos seguir os estudos com Feature Selection

03 - Separação dos Dados¶

In [19]:
## bibliotecas necessárias

from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler
from category_encoders import TargetEncoder, OneHotEncoder
from sklearn.feature_selection import SelectKBest, f_classif, VarianceThreshold
from sklearn.utils.class_weight import compute_class_weight
from sklearn.metrics import log_loss, roc_auc_score, precision_score, recall_score, f1_score, accuracy_score
from sklearn.linear_model import LogisticRegression
In [20]:
numerical_cols = bank.select_dtypes(exclude='O').columns.tolist()
categorical_cols = bank.select_dtypes(include='object').columns.tolist()

numerical_cols = [col for col in numerical_cols if col not in ['INADIMPLENCIA']]
In [21]:
X = bank.drop(['INADIMPLENCIA'], axis=1)
y = bank['INADIMPLENCIA']
In [22]:
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state = 42, test_size=0.2)
In [23]:
X_train.shape, X_test.shape, y_train.shape, y_test.shape
Out[23]:
((8368, 13), (2093, 13), (8368,), (2093,))

Ponto de Atenção: Sempre tratar os dados APÓS divisão dos dados para evita Data Leakage¶

04 - Pipeline e Treinamento¶

In [24]:
from sklearn.utils.class_weight import compute_class_weight ## 2 - segunda etapa para tentar melhorar o modelo - inserindo pesos

class_weights = compute_class_weight('balanced', classes=np.unique(y_train), y = y_train)
weights_dict = {class_label: weight for class_label, weight in zip(np.unique(y_train), class_weights)}
In [25]:
numeric_transformer = Pipeline(steps = [('imputer', SimpleImputer(strategy='median'))])
categorical_transformer = Pipeline(steps = [('encoder', TargetEncoder())])

preprocessor = ColumnTransformer(
    transformers = [
        ('num', numeric_transformer, numerical_cols),
        ('cat', categorical_transformer, categorical_cols)
    ]
)

pipeline = Pipeline(steps=[
    ('preprocessor', preprocessor),
    ('variance_threshold', VarianceThreshold()),  # Adicionado para remover features constantes
    ('select', SelectKBest(f_classif, k=10)), ## 1 - após rodar inicialmente "sem" - inserindo select KBest para tentar melhorar o modelo
    ('classifier', LogisticRegression(class_weight=weights_dict, max_iter=1000))
])

pipeline.fit(X_train, y_train)
Out[25]:
Pipeline(steps=[('preprocessor',
                 ColumnTransformer(transformers=[('num',
                                                  Pipeline(steps=[('imputer',
                                                                   SimpleImputer(strategy='median'))]),
                                                  ['CARTAO_CRED', 'IDADE',
                                                   'TEMPO_RESIDENCIA',
                                                   'DEPENDENTES',
                                                   'DEPREC_MAJOR',
                                                   'DEPREC_MINOR',
                                                   'CASA_PROPRIA',
                                                   'RENDA_MENSAL', 'AUTONOMO',
                                                   'RENDA/DEPENDENTES',
                                                   'EXP_INC',
                                                   'DESPESA_MENSAL_CC',
                                                   'REGISTRO_GASTOS']),
                                                 ('cat',
                                                  Pipeline(steps=[('encoder',
                                                                   TargetEncoder())]),
                                                  [])])),
                ('variance_threshold', VarianceThreshold()),
                ('select', SelectKBest()),
                ('classifier',
                 LogisticRegression(class_weight={0: 0.5520517218630426,
                                                  1: 5.302915082382763},
                                    max_iter=1000))])
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
Pipeline(steps=[('preprocessor',
                 ColumnTransformer(transformers=[('num',
                                                  Pipeline(steps=[('imputer',
                                                                   SimpleImputer(strategy='median'))]),
                                                  ['CARTAO_CRED', 'IDADE',
                                                   'TEMPO_RESIDENCIA',
                                                   'DEPENDENTES',
                                                   'DEPREC_MAJOR',
                                                   'DEPREC_MINOR',
                                                   'CASA_PROPRIA',
                                                   'RENDA_MENSAL', 'AUTONOMO',
                                                   'RENDA/DEPENDENTES',
                                                   'EXP_INC',
                                                   'DESPESA_MENSAL_CC',
                                                   'REGISTRO_GASTOS']),
                                                 ('cat',
                                                  Pipeline(steps=[('encoder',
                                                                   TargetEncoder())]),
                                                  [])])),
                ('variance_threshold', VarianceThreshold()),
                ('select', SelectKBest()),
                ('classifier',
                 LogisticRegression(class_weight={0: 0.5520517218630426,
                                                  1: 5.302915082382763},
                                    max_iter=1000))])
ColumnTransformer(transformers=[('num',
                                 Pipeline(steps=[('imputer',
                                                  SimpleImputer(strategy='median'))]),
                                 ['CARTAO_CRED', 'IDADE', 'TEMPO_RESIDENCIA',
                                  'DEPENDENTES', 'DEPREC_MAJOR', 'DEPREC_MINOR',
                                  'CASA_PROPRIA', 'RENDA_MENSAL', 'AUTONOMO',
                                  'RENDA/DEPENDENTES', 'EXP_INC',
                                  'DESPESA_MENSAL_CC', 'REGISTRO_GASTOS']),
                                ('cat',
                                 Pipeline(steps=[('encoder', TargetEncoder())]),
                                 [])])
['CARTAO_CRED', 'IDADE', 'TEMPO_RESIDENCIA', 'DEPENDENTES', 'DEPREC_MAJOR', 'DEPREC_MINOR', 'CASA_PROPRIA', 'RENDA_MENSAL', 'AUTONOMO', 'RENDA/DEPENDENTES', 'EXP_INC', 'DESPESA_MENSAL_CC', 'REGISTRO_GASTOS']
SimpleImputer(strategy='median')
[]
TargetEncoder()
VarianceThreshold()
SelectKBest()
LogisticRegression(class_weight={0: 0.5520517218630426, 1: 5.302915082382763},
                   max_iter=1000)
In [26]:
from sklearn.preprocessing import FunctionTransformer
from sklearn.model_selection import cross_val_score


# Defina a lista de valores de k que você deseja testar
valores_k = [3, 6, 10, 12]

# Crie listas vazias para armazenar os resultados
resultados = []

for k in valores_k:
    # Crie o pipeline
    pipeline = Pipeline(steps=[
        ('preprocessor', preprocessor),
        ('variance_threshold', VarianceThreshold()),  # Remover features constantes
        ('select', SelectKBest(f_classif, k=k)),
        ('classifier', LogisticRegression(class_weight=weights_dict, max_iter=1000))
    ])

    # Treine o pipeline
    pipeline.fit(X_train, y_train)

    # Avalie o pipeline usando cross-validation
    scores = cross_val_score(pipeline, X_train, y_train, cv=5)  # Use 5-fold cross-validation
    mean_score = np.mean(scores)

    # Armazene os resultados
    resultados.append((k, mean_score))

# Exiba os resultados
for k, score in resultados:
    print(f"Para k={k}, a média dos scores é: {score}")

# Encontre o melhor valor de k baseado nos resultados
melhor_k, melhor_score = max(resultados, key=lambda x: x[1])
print(f"Melhor valor de k encontrado: {melhor_k} com score médio de: {melhor_score}")
Para k=3, a média dos scores é: 0.5702618936928562
Para k=6, a média dos scores é: 0.6362374232397178
Para k=10, a média dos scores é: 0.6314589506113328
Para k=12, a média dos scores é: 0.5896428696401703
Melhor valor de k encontrado: 6 com score médio de: 0.6362374232397178

Conseguimos Encontrar o Melhor Valor De K¶

In [27]:
from sklearn.pipeline import Pipeline
from sklearn.feature_selection import SelectKBest, f_classif
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_predict
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
import numpy as np

# Defina o melhor valor de k encontrado
melhor_k = 6

# Crie o pipeline usando o melhor valor de k
pipeline = Pipeline(steps=[
    ('preprocessor', preprocessor),
    ('variance_threshold', VarianceThreshold()),  # Remover features constantes
    ('select', SelectKBest(f_classif, k=melhor_k)),
    ('classifier', LogisticRegression(class_weight=weights_dict, max_iter=1000))
])

# Treine o pipeline
pipeline.fit(X_train, y_train)

# Obtenha as predições usando validação cruzada
predicoes = cross_val_predict(pipeline, X_train, y_train, cv=5)

# Calcule as métricas
acuracia = accuracy_score(y_train, predicoes)
precisao = precision_score(y_train, predicoes)
recall = recall_score(y_train, predicoes)
f1 = f1_score(y_train, predicoes)

# Exiba os resultados
print(f"Acurácia: {acuracia}")
print(f"Precisão: {precisao}")
print(f"Recall: {recall}")
print(f"F1-Score: {f1}")
Acurácia: 0.6362332695984704
Precisão: 0.12024250589424049
Recall: 0.4524714828897338
F1-Score: 0.18999467802022352

Após Visualizar resultados Não Tão Bons - Vamos Lidar Agora Com Dados Desbalanceados¶

Cross-Validation Avançada: Usando StratifiedKFold para manter a proporção das classes em cada fold.¶

In [28]:
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import StratifiedKFold
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score

# Defina o novo classificador
classificador = RandomForestClassifier(class_weight=weights_dict, n_estimators=100, random_state=42)

# Crie o pipeline usando o melhor valor de k
pipeline = Pipeline(steps=[
    ('preprocessor', preprocessor),
    ('variance_threshold', VarianceThreshold()),  # Remover features constantes
    ('select', SelectKBest(f_classif, k=melhor_k)),
    ('classifier', classificador)
])

# Avaliação com validação cruzada estratificada
skf = StratifiedKFold(n_splits=5)
scores = {'accuracy': [], 'precision': [], 'recall': [], 'f1': []}

for train_index, test_index in skf.split(X_train, y_train):
    X_fold_train, X_fold_test = X_train.iloc[train_index], X_train.iloc[test_index]
    y_fold_train, y_fold_test = y_train.iloc[train_index], y_train.iloc[test_index]
    
    pipeline.fit(X_fold_train, y_fold_train)
    predicoes = pipeline.predict(X_fold_test)
    
    scores['accuracy'].append(accuracy_score(y_fold_test, predicoes))
    scores['precision'].append(precision_score(y_fold_test, predicoes))
    scores['recall'].append(recall_score(y_fold_test, predicoes))
    scores['f1'].append(f1_score(y_fold_test, predicoes))

# Exiba os resultados médios
print(f"Acurácia média: {np.mean(scores['accuracy'])}")
print(f"Precisão média: {np.mean(scores['precision'])}")
print(f"Recall médio: {np.mean(scores['recall'])}")
print(f"F1-Score médio: {np.mean(scores['f1'])}")
Acurácia média: 0.903680637234423
Precisão média: 0.21666666666666665
Recall médio: 0.007602999274369105
F1-Score médio: 0.01465056083367726

Aplicando SMOTE Como Forma de Lidar Com Dados Desbalanceados¶

In [29]:
from imblearn.over_sampling import SMOTE
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import StratifiedKFold
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score

# Aplicar SMOTE para balancear as classes
smote = SMOTE(random_state=42)
X_train_res, y_train_res = smote.fit_resample(X_train, y_train)

# Novo classificador
classificador = RandomForestClassifier(class_weight=weights_dict, n_estimators=100, random_state=42)

# Pipeline com melhor k
pipeline = Pipeline(steps=[
    ('preprocessor', preprocessor),
    ('variance_threshold', VarianceThreshold()),  # Remover features constantes
    ('select', SelectKBest(f_classif, k=melhor_k)),
    ('classifier', classificador)
])

# Avaliação com validação cruzada estratificada
skf = StratifiedKFold(n_splits=5)
scores = {'accuracy': [], 'precision': [], 'recall': [], 'f1': []}

for train_index, test_index in skf.split(X_train_res, y_train_res):
    X_fold_train, X_fold_test = X_train_res.iloc[train_index], X_train_res.iloc[test_index]
    y_fold_train, y_fold_test = y_train_res.iloc[train_index], y_train_res.iloc[test_index]
    
    pipeline.fit(X_fold_train, y_fold_train)
    predicoes = pipeline.predict(X_fold_test)
    
    scores['accuracy'].append(accuracy_score(y_fold_test, predicoes))
    scores['precision'].append(precision_score(y_fold_test, predicoes))
    scores['recall'].append(recall_score(y_fold_test, predicoes))
    scores['f1'].append(f1_score(y_fold_test, predicoes))

# Exibir os resultados médios
print(f"Acurácia média: {np.mean(scores['accuracy'])}")
print(f"Precisão média: {np.mean(scores['precision'])}")
print(f"Recall médio: {np.mean(scores['recall'])}")
print(f"F1-Score médio: {np.mean(scores['f1'])}")
Acurácia média: 0.817260711434787
Precisão média: 0.8178422863976882
Recall médio: 0.8146270801222603
F1-Score médio: 0.814516585287274
In [ ]: